﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using static 序列化工具.类型判断器;

namespace 序列化工具
{
    public static class 反序列化器
    {

        /// <summary>
        /// 传入一个实例，并将其反序列化，传出反序列化后的实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="对象实例"></param>
        /// <param name="实例信息集"></param>
        /// <returns></returns>
        public static T 为实例添加信息<T>(T 对象实例, List<值结构> 实例信息集) where T : class
        {

            反序列化对象(对象实例, 实例信息集,"" );
            return 对象实例;
        }
        
        /// <summary>
        /// 进行反序列化，该方法为所有未知对象处理的通用方法
        /// </summary>
        /// <param name="对象实例"></param>
        /// <param name="实例信息集"></param>
        /// <param name="根路径"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private static object 反序列化对象(object 对象实例, List<值结构> 实例信息集, string 根路径)
        {
            var 对象类信息 = 对象实例.GetType();
            var 对象名称 = 对象类信息.FullName;
            根路径 += $"<{对象名称}>";
            var 对象信息 = 对象实例.GetType().GetFields();
            foreach (var 信息 in 对象信息)
            {
                var 对象类型 = 类型判断器.基础类型判断(信息.FieldType);
                var 路径拼接 = 对象路径拼接(根路径, 信息.Name, 对象类型, 信息, 实例信息集);
                string 检测 = "<序列化工具.数据>词汇表#Dict[0].Value#<序列化工具.单词>数据表#List[0]#<序列化工具.子数据>数据名称";
                if (路径拼接 == 检测) { throw new Exception("检测成功"); }
                if (路径拼接 == null) { continue; }//若为NULL表示实例信息集找不到此数据
                通过类型处理数据(对象实例, 信息, 实例信息集, 路径拼接, 对象类型);
           }
            return 对象实例;
        }

        /// <summary>
        /// 通过类型的不同，处理数据并为对象附加值
        /// </summary>
        /// <param name="对象实例"></param>
        /// <param name="成员信息"></param>
        /// <param name="实例信息集"></param>
        /// <param name="根路径"></param>
        /// <param name="对象类型"></param>
        /// <returns></returns>
        private static object 通过类型处理数据(object 对象实例, FieldInfo 成员信息, List<值结构> 实例信息集, string 根路径, 类型判断器.类型 对象类型)
        {
            switch (对象类型)
            {
                case 类型判断器.类型.int数字:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.float数字:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.double数字:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.decimal数字:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.long数字:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.bool值:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.字符串:
                    设置数据(对象实例, 成员信息, 加载普通数据(实例信息集, 根路径));
                    break;
                case 类型判断器.类型.类:
                    break;
                case 类型判断器.类型.基本类型:
                    break;
                case 类型判断器.类型.列表:
                    设置数据(对象实例, 成员信息, 加载并实例化列表对象(成员信息,实例信息集, 根路径));
                    break;
                case 类型判断器.类型.字典:
                    设置数据(对象实例, 成员信息, 加载并实例化字典对象(成员信息, 实例信息集, 根路径));
                    break;
                case 类型判断器.类型.未知:
                    var 判断结果 = 判断类型是否已实例化(成员信息, 实例信息集, 根路径, 对象实例);
                    if (!判断结果.已实例化) { return  对象实例; }
                    反序列化对象(判断结果.实例化子对象, 实例信息集, 根路径);
                    成员信息.SetValue(对象实例,判断结果.实例化子对象);
                    break;
            }
            return 对象实例;
        }

        /// <summary>
        /// 判断类型的实例是否存在，即在此处检测，是否在序列化后的文档中有相关实例，并传回相关的信息
        /// </summary>
        /// <param name="成员信息"></param>
        /// <param name="实例信息集"></param>
        /// <param name="根路径"></param>
        /// <param name="对象实例"></param>
        /// <returns></returns>
        private static (bool 已实例化,object 实例化子对象,string 新根路径) 判断类型是否已实例化(FieldInfo 成员信息, List<值结构> 实例信息集, string 根路径, object 对象实例)
        {
            var 子类型 = 成员信息.FieldType.FullName;
            根路径 += $"<{子类型}>";
            bool 存在数据 = 实例信息集.Find(x => x.绝对路径.Contains(根路径))!=null ? true : false;
            var 实例化子对象 = Activator.CreateInstance(成员信息.FieldType);
            return (存在数据,实例化子对象,根路径);
        }

        public static object 加载并实例化类对象()
        {
            return null;
        }
        /// <summary>
        /// 根据设定好的规则，为每种类型的对象拼接路径，并在此处检测，是否在序列化后的文档中有相关实例，若没有实例，则回传Null。
        /// </summary>
        /// <param name="路径"></param>
        /// <param name="子路径"></param>
        /// <param name="类型"></param>
        /// <param name="信息"></param>
        /// <param name="实例信息集"></param>
        /// <returns></returns>
        private static string 对象路径拼接(string 路径, string 子路径, 类型判断器.类型 类型, FieldInfo 信息, List<值结构> 实例信息集)
        {
            Debug.WriteLine($"正在反序列化路径 : {路径.Replace('#', '/')}");

            string 输出路径 = null;
            switch (类型)
            {
                case 类型判断器.类型.int数字:

                    输出路径 =  $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.float数字:
                    输出路径 =  $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.double数字:
                    输出路径 = $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.decimal数字:
                    输出路径 = $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.long数字:
                    输出路径 = $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.bool值:
                    输出路径 = $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.字符串:
                    输出路径 = $"{路径}{子路径}";
                    if (实例信息集.Find(x => x.绝对路径.Contains(输出路径)) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    break;
                case 类型判断器.类型.类:
                    break;
                case 类型判断器.类型.基本类型:
                    break;
                case 类型判断器.类型.列表:
                    if (实例信息集.Find(x => x.绝对路径.Contains($"{路径}{子路径}")) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    输出路径 = $"{路径}{子路径}#List"+"[{0}]";
                    break;
                case 类型判断器.类型.字典:
                    if (实例信息集.Find(x => x.绝对路径.Contains($"{路径}{子路径}")) == null) { Debug.WriteLine($"路径未被配置 : {路径.Replace('#', '/')}"); return null; }
                    输出路径 = $"{路径}{子路径}#Dict"+"[{0}].";
                    break;
                case 类型判断器.类型.未知:
                    输出路径 = $"{路径}{子路径}#";
                    break;

            }

            return 输出路径;
        }

        public static object 加载普通数据(List<值结构> 值结构组, string 查找路径)
        {
            var 查找结果 = 值结构组.Find(x => x.绝对路径 == 查找路径);
            if (查找结果 ==null) { throw new Exception("在已加载的数据中未找到值成员", new NullReferenceException());  }
            return 查找结果.值文本;
        }

        /// <summary>
        /// 如果对象的数据是系统自带的值类型或字符串，则可以通过此处设置数据
        /// </summary>
        /// <param name="对象"></param>
        /// <param name="成员信息"></param>
        /// <param name="设置值"></param>
        private static void 设置数据(object 对象, FieldInfo 成员信息, object 设置值)
        {
            成员信息.SetValue(对象, Convert.ChangeType(设置值, 成员信息.FieldType));
        }

        private static IDictionary 加载并实例化字典对象(FieldInfo 成员信息, List<值结构> 实例信息集, string 查找路径)
        {
            bool 能查找到数据 = true;
            int 列表指针 = 0;
            var 字典对象 = (IDictionary)Activator.CreateInstance(成员信息.FieldType);
            //此处需要判断是否能查找到数据，即在序列化的文档中是否有实例，因为只能通过指针去读取，就只能不断通过指针去检测。
            while (能查找到数据)
            {
                var Key路径 = string.Format(查找路径, 列表指针)+ "Key";
                var Value路径 = string.Format(查找路径, 列表指针)+ "Value";

                //对字典泛型进行判断，如果是子类
                var 字典泛型 = 字典对象.GetType().GenericTypeArguments;
                var Key类型 = 类型判断器.基础类型判断(字典泛型[0]);
                var Value类型 = 类型判断器.基础类型判断(字典泛型[1]);
                object Key,Value ;

                //只有对这三种类型才需要进行再次的实例化判断，否则就可以直接赋值，如果都进行实例化判断的话，第一浪费性能，第二要调用的方法必须有FieldType，如果改动此项将造成更大的
                //逻辑修改，故使用该判断方法，另外，这里的Key和Value必须分别进行处理，这样才能节省一些代码，避免每个if，都去Add值。
                if (Key类型 == 类型判断器.类型.未知 || Key类型 == 类型判断器.类型.字典 || Key类型 == 类型判断器.类型.列表)
                {
                    //处理Key，引用设置
                    var 类似结果 = 实例信息集.Find(x => x.绝对路径.Contains(Key路径));
                    if (类似结果 == null) { 能查找到数据 = false; break; }
                    var 实例子对象 = Activator.CreateInstance(字典泛型[0]);
                    Key = 反序列化对象(实例子对象, 实例信息集, Key路径 + "#");//#代表是一个子类
                }
                else
                {
                    //处理Key，非引用（或string）设置
                    var Key查找结果 = 实例信息集.Find(x => x.绝对路径 == Key路径);
                    if (Key查找结果 == null) { 能查找到数据 = false; break; }
                    Key = Convert.ChangeType(Key查找结果.值文本, Key查找结果.类型);
                }


                if (Value类型 == 类型判断器.类型.未知 || Key类型 == 类型判断器.类型.字典 || Key类型 == 类型判断器.类型.列表)
                {
                    //处理Value，引用设置
                    var 类似结果 = 实例信息集.Find(x => x.绝对路径.Contains(Value路径));
                    if (类似结果 == null) { 能查找到数据 = false; break; }
                    var 实例子对象 = Activator.CreateInstance(字典泛型[1]);
                    Value = 反序列化对象(实例子对象, 实例信息集, Value路径 + "#");//#代表是一个子类
                }
                else
                {
                    //处理Value，非引用（或string）设置
                    var Value查找结果 = 实例信息集.Find(x => x.绝对路径 == Value路径);
                    if (Value查找结果 == null) { 能查找到数据 = false; break; }
                    Value = Convert.ChangeType(Value查找结果.值文本, Value查找结果.类型);

                }

                字典对象.Add(Key, Value);
                列表指针++;


            }
            return 字典对象;
        }
        private static IList 加载并实例化列表对象(FieldInfo 成员信息,List<值结构> 实例信息集, string 根路径)
        {

            bool 能查找到数据 = true;
            int 列表指针 = 0;
            var 列表对象 = (IList)Activator.CreateInstance(成员信息.FieldType);
            //对列表泛型进行判断，如果是子类
            var 列表泛型 = 列表对象.GetType().GenericTypeArguments.FirstOrDefault();
            var 类型 = 类型判断器.基础类型判断(列表泛型);
            //此处需要判断是否能查找到数据，即在序列化的文档中是否有实例，因为只能通过指针去读取，就只能不断通过指针去检测。
            while (能查找到数据)
            {
                var 路径拼接 = string.Format(根路径, 列表指针);

                //只有对这三种类型才需要进行再次的实例化判断，否则就可以直接赋值，如果都进行实例化判断的话，第一浪费性能，第二要调用的方法必须有FieldType，如果改动此项将造成更大的
                //逻辑修改，故使用该判断方法
                //引用设置
                if (类型 == 类型判断器.类型.未知 || 类型 == 类型判断器.类型.字典 || 类型 == 类型判断器.类型.列表)
                {
                    var 类似结果 = 实例信息集.Find(x => x.绝对路径.Contains( 路径拼接));
                    if (类似结果 == null) { 能查找到数据 = false; break; }
                    var 实例子对象 = Activator.CreateInstance(列表泛型);
                    var 结果 = 反序列化对象(实例子对象, 实例信息集, 路径拼接+"#");//#代表是一个子类
                    列表对象.Add(Convert.ChangeType(结果, 结果.GetType()));
                    列表指针++;
              
                }
                else
                {
                    //非引用（或string）设置
                    var 查找结果 = 实例信息集.Find(x => x.绝对路径 == 路径拼接);
                    if (查找结果 == null) { 能查找到数据 = false; break; }
                    列表对象.Add(Convert.ChangeType(查找结果.值文本, 查找结果.类型));
                    列表指针++;
                }

               
            }
            return 列表对象;
        }


    }
}
